# -*- coding: utf-8 -*-
#
import builtins
import time
from django.utils.translation import ugettext as _
from django.conf import settings
from rest_framework.permissions import AllowAny
from rest_framework.generics import CreateAPIView
from rest_framework.serializers import ValidationError
from rest_framework.response import Response

from authentication.sms_verify_code import VerifyCodeUtil
from common.exceptions import JMSException
from common.permissions import IsValidUser, NeedMFAVerify, IsAppUser
from users.models.user import MFAType
from ..serializers import OtpVerifySerializer
from .. import serializers
from .. import errors
from ..mixins import AuthMixin


__all__ = ['MFAChallengeApi', 'UserOtpVerifyApi', 'SendSMSVerifyCodeApi', 'MFASelectTypeApi']


class MFASelectTypeApi(AuthMixin, CreateAPIView):
    permission_classes = (AllowAny,)
    serializer_class = serializers.MFASelectTypeSerializer

    def perform_create(self, serializer):
        mfa_type = serializer.validated_data['type']
        if mfa_type == MFAType.SMS_CODE:
            user = self.get_user_from_session()
            user.send_sms_code()


class MFAChallengeApi(AuthMixin, CreateAPIView):
    permission_classes = (AllowAny,)
    serializer_class = serializers.MFAChallengeSerializer

    def perform_create(self, serializer):
        try:
            user = self.get_user_from_session()
            code = serializer.validated_data.get('code')
            mfa_type = serializer.validated_data.get('type', MFAType.OTP)

            valid = user.check_mfa(code, mfa_type=mfa_type)
            if not valid:
                self.request.session['auth_mfa'] = ''
                raise errors.MFAFailedError(
                    username=user.username, request=self.request, ip=self.get_request_ip()
                )
            else:
                self.request.session['auth_mfa'] = '1'
        except errors.AuthFailedError as e:
            data = {"error": e.error, "msg": e.msg}
            raise ValidationError(data)
        except errors.NeedMoreInfoError as e:
            return Response(e.as_data(), status=200)

    def create(self, request, *args, **kwargs):
        super().create(request, *args, **kwargs)
        return Response({'msg': 'ok'})


class UserOtpVerifyApi(CreateAPIView):
    permission_classes = (IsValidUser,)
    serializer_class = OtpVerifySerializer

    def get(self, request, *args, **kwargs):
        return Response({'code': 'valid', 'msg': 'verified'})

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        code = serializer.validated_data["code"]

        if request.user.check_mfa(code):
            request.session["MFA_VERIFY_TIME"] = int(time.time())
            return Response({"ok": "1"})
        else:
            return Response({"error": _("Code is invalid")}, status=400)

    def get_permissions(self):
        if self.request.method.lower() == 'get' and settings.SECURITY_VIEW_AUTH_NEED_MFA:
            self.permission_classes = [NeedMFAVerify]
        return super().get_permissions()


class SendSMSVerifyCodeApi(AuthMixin, CreateAPIView):
    permission_classes = (AllowAny,)

    def create(self, request, *args, **kwargs):
        user = self.get_user_from_session()
        timeout = user.send_sms_code()
        return Response({'code': 'ok','timeout': timeout})
